using System;
using System.Xml;

using DesignByContract;

using Outcoding.GraphGenerator.Entities;
using Outcoding.GraphGenerator.Util.Logging;

namespace Outcoding.GraphGenerator.Composition {
    public class IndustryBuilder : BuilderBase {

        private struct Attributes{
            public const string Name = "name";
            public const string IntroductorySlide = "introductory-slide";

            public const string fontColorAttr = "font-color";
            public const string fontDecorationAttr = "font-decoration";
            public const string fontNameAttr = "font-name";
            public const string fontSizeAttr = "font-size";
            public const string hAlignAttr = "halign";
        }

        private static readonly string mNodeName = XmlTagNames.industry.ToString();

        private readonly string mNodePath = "/presentation/" + mNodeName;

        private XmlNode mNode;

        public override void SelectNode(XmlDocument document) {
            Check.Require(document != null, "XmlDocument cannot be null.");

            if (document != null) mNode = document.SelectSingleNode(mNodePath);

            Check.Ensure(mNode != null, "Presentation node could not be created.");
        }

        public override void Compose() {
            try {
                BuildObject(mNode);
            } catch (PreconditionException preExc) {
                LogManager.Instance.LogWarning("Industry entity could not be created; process aborted.", preExc);
            }
        }

        public override void Compose(XmlNode node) {
            throw new Exception("The method or operation is not implemented.");
        }

        public override void AppendToParent(object parent) {
            Presentation presentation = (Presentation)parent;
            presentation.Industry = (Industry)this.Product;
        }

        private void BuildObject(XmlNode industryXmlNode) {
            Industry industry = new Industry();
            try {
                industry.Name = ParseNameAttribute(industryXmlNode);
                if (industryXmlNode.Attributes[Attributes.IntroductorySlide] != null)
                    industry.IsIntroductory = ParseIsIntroductoryAttribute(industryXmlNode);
                if (industryXmlNode.Attributes[Attributes.fontNameAttr] != null)
                    industry.FontName = ParseFontNameAttribute(industryXmlNode);
                if (industryXmlNode.Attributes[Attributes.fontSizeAttr] != null)
                    industry.FontSize = ParseFontSizeAttribute(industryXmlNode);
                if (industryXmlNode.Attributes[Attributes.fontDecorationAttr] != null)
                {
                    industry.IsFontBold = ParseIsFontBoldAttribute(industryXmlNode);
                    industry.IsFontItalic = ParseIsFontItalicAttribute(industryXmlNode);
                    industry.IsFontUnderline = ParseIsFontUnderlineAttribute(industryXmlNode);
                }
                if (industryXmlNode.Attributes[Attributes.fontColorAttr] != null)
                    industry.Color = ParseColorAttribute(industryXmlNode);
                if (industryXmlNode.Attributes[Attributes.hAlignAttr] != null)
                    industry.HorizontalAlignment = ParseHorizontalAlignmentAttribute(industryXmlNode);

            } catch (DesignByContract.PreconditionException preExc) {
                //log error
                industry = null;
                throw;
            }

            mProduct = industry;
        }

        private string ParseNameAttribute(XmlNode industryXmlNode) {
            Check.Require(industryXmlNode.Attributes[Attributes.Name] != null, Attributes.Name + " attribute not present.");
            return industryXmlNode.Attributes[Attributes.Name].Value;
        }

        private bool ParseIsIntroductoryAttribute(XmlNode industryXmlNode) {
            Check.Require(industryXmlNode.Attributes[Attributes.IntroductorySlide] != null, Attributes.IntroductorySlide + " attribute not present");
            return Boolean.Parse(industryXmlNode.Attributes[Attributes.IntroductorySlide].Value);
        }
        private string ParseFontNameAttribute(XmlNode industryXmlNode)
        {
            Check.Require(industryXmlNode.Attributes[Attributes.fontNameAttr] != null, "font-name attribute not present");
            return industryXmlNode.Attributes[Attributes.fontNameAttr].Value;
        }

        private int ParseFontSizeAttribute(XmlNode industryXmlNode)
        {
            Check.Require(industryXmlNode.Attributes[Attributes.fontSizeAttr] != null, "font-size attribute not present");
            return Int32.Parse(industryXmlNode.Attributes[Attributes.fontSizeAttr].Value);
        }

        private bool ParseIsFontBoldAttribute(XmlNode industryXmlNode)
        {
            Check.Require(industryXmlNode.Attributes[Attributes.fontDecorationAttr] != null, "font-decoration attribute not present");
            return industryXmlNode.Attributes[Attributes.fontDecorationAttr].Value.Contains("bold");
        }

        private bool ParseIsFontItalicAttribute(XmlNode industryXmlNode)
        {
            Check.Require(industryXmlNode.Attributes[Attributes.fontDecorationAttr] != null, "font-decoration attribute not present");
            return industryXmlNode.Attributes[Attributes.fontDecorationAttr].Value.Contains("italic");
        }

        private bool ParseIsFontUnderlineAttribute(XmlNode industryXmlNode)
        {
            Check.Require(industryXmlNode.Attributes[Attributes.fontDecorationAttr] != null, "font-decoration attribute not present");
            return industryXmlNode.Attributes[Attributes.fontDecorationAttr].Value.Contains("underline");
        }

        private PPAlignment ParseHorizontalAlignmentAttribute(XmlNode industryXmlNode)
        {
            Check.Require(industryXmlNode.Attributes[Attributes.hAlignAttr] != null, "horizontal alignment attribute not present");
            return ConvertHorizontalAlignFromName(industryXmlNode.Attributes[Attributes.hAlignAttr].Value);
        }

        private string ParseTextValue(XmlNode industryXmlNode)
        {
            return industryXmlNode.InnerText.Trim();
        }

        private long ParseColorAttribute(XmlNode industryXmlNode)
        {
            Check.Require(industryXmlNode.Attributes[Attributes.fontColorAttr] != null, "color attribute not present");

            return Entities.Util.ColorTranslation(industryXmlNode.Attributes[Attributes.fontColorAttr].Value);
        }

        private PPAlignment ConvertHorizontalAlignFromName(string value)
        {
            switch (value)
            {
                case "ppAlignCenter":
                    return PPAlignment.ppAlignCenter;
                case "ppAlignDistribute":
                    return PPAlignment.ppAlignDistribute;
                case "ppAlignJustify":
                    return PPAlignment.ppAlignJustify;
                case "ppAlignLeft":
                    return PPAlignment.ppAlignLeft;
                case "ppAlignRight":
                    return PPAlignment.ppAlignRight;
            }
            return PPAlignment.ppAlignUnknown;
        }
    }
}
